package com.waigoulin.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.google.common.eventbus.EventBus;
import com.waigoulin.common.constants.Constants;
import com.waigoulin.dao.IOrderDao;
import com.waigoulin.domain.po.PayOrder;
import com.waigoulin.domain.req.ShopCartReq;
import com.waigoulin.domain.res.PayOrderRes;
import com.waigoulin.domain.vo.ProductVO;
import com.waigoulin.service.IOrderService;
import com.waigoulin.service.rpc.ProductRPC;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @FileName OrderServiceImpl
 * @Description 订单服务
 * @Author waigoulin
 * @date 2025-07-26
 **/
@Slf4j
@Service
public class OrderServiceImpl implements IOrderService {

    @Value("${alipay.notify_url}")
    private String notifyUrl;

    @Value("${alipay.return_url}")
    private String returnUrl;

    @Resource
    private IOrderDao orderDao;

    @Resource
    private ProductRPC productRPC;

    @Resource
    private AlipayClient alipayClient;

    @Resource
    private EventBus eventBus;

    @Override
    public PayOrderRes createOrder(ShopCartReq shopCartReq) throws Exception {
        // 1. 查询当前用户是否存在未支付的订单或掉单订单
        // 掉单：用户提交订单后，系统未正常创建订单记录；或订单提交成功，但后续流程（如库存扣减、物流单生成）中断，导致订单 “消失” 或状态停滞。
        // 即只有流水单，没有支付单
        PayOrder payOrderRequest = PayOrder.builder()
                .userId(shopCartReq.getUserId())
                .productId(shopCartReq.getProductId())
                .build();
        PayOrder unpaidOrder = orderDao.queryUnPayOrder(payOrderRequest);
        // 如果存在未支付订单或调单订单
        if (unpaidOrder != null && Constants.OrderStatusEnum.PAY_WAIT.getCode().equals(unpaidOrder.getStatus())) {
            // 存在未支付订单，订单状态为PAY_WAIT，等待支付
            // 需要将未支付的订单返回给用户支付，用户只需要知道订单的id和支付链接
            log.info("创建订单-存在，已存在未支付订单，userId:{} productId:{} orderId:{}", shopCartReq.getUserId(), shopCartReq.getProductId(), unpaidOrder.getOrderId());
            return PayOrderRes.builder()
                    // .userId(unpaidOrder.getUserId()) 用户无需知道自己的用户id
                    .orderId(unpaidOrder.getOrderId())
                    .payUrl(unpaidOrder.getPayUrl())
                    // .orderStatusEnum(Constants.OrderStatusEnum.PAY_WAIT) 用户也无需知道订单的状态
                    .build();
        } else if (unpaidOrder != null && Constants.OrderStatusEnum.CREATE.getCode().equals(unpaidOrder.getStatus())) {
            // 存在掉单订单，需要重新获得支付单
            // 需要将新创建的订单返回给用户支付，用户只需要知道订单的id和支付链接
            PayOrder payOrder = doPrepareOrder(unpaidOrder.getProductId(), unpaidOrder.getProductName(), unpaidOrder.getOrderId(), unpaidOrder.getTotalAmount());
            log.info("创建订单-存在，存在未创建支付单订单，创建支付单开始 userId:{} productId:{} orderId:{}", shopCartReq.getUserId(), shopCartReq.getProductId(), unpaidOrder.getOrderId());
            return PayOrderRes.builder()
                    .orderId(payOrder.getOrderId())
                    .payUrl(payOrder.getPayUrl())
                    .build();
        }

        // 2. 查询商品并创建订单（本地的流水单和支付宝的支付单）
        // 2.1 查询商品
        ProductVO productVO = productRPC.queryProductsByProductId(shopCartReq.getProductId());
        // 2.2 创建流水单
        String orderId = RandomStringUtils.randomNumeric(16);
        orderDao.insert(PayOrder.builder()
                        .userId(shopCartReq.getUserId())
                        .orderId(orderId)
                        .productId(shopCartReq.getProductId())
                        .productName(productVO.getProductName())
                        .orderTime(LocalDateTime.now())
                        .totalAmount(productVO.getPrice())
                        .status(Constants.OrderStatusEnum.CREATE.getCode()) // 创建的流水单默认是CREATE状态，成功创建支付单后才会调用方法修改为PAY_WAIT状态
                        .build());
        // 2.3 创建支付单
        PayOrder payOrder = doPrepareOrder(productVO.getProductId(), productVO.getProductName(), orderId, productVO.getPrice());
        log.info("创建订单-完成，生成支付单，userId:{} orderId:{} payUrl:{}", payOrder.getUserId(), payOrder.getOrderId(), payOrder.getPayUrl());

        // 需要将未支付的订单返回给用户支付，用户只需要知道订单的id和支付链接
        return PayOrderRes.builder()
                .orderId(orderId)
                .payUrl(payOrder.getPayUrl())
                .build();
    }

    private PayOrder doPrepareOrder(String productId, String productName, String orderId, BigDecimal totalAmount) throws AlipayApiException {
        // 支付宝支付请求，设置回调链接和返回链接
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setNotifyUrl(notifyUrl);
        request.setReturnUrl(returnUrl);

        // 设置订单具体参数
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", orderId);
        bizContent.put("total_amount", totalAmount.toString());
        bizContent.put("subject", productName);
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
        request.setBizContent(bizContent.toString());

        // 执行请求并解析响应
        String form = alipayClient.pageExecute(request).getBody();

        // 更新支付单对应的流水单的状态
        // 准备更新信息
        PayOrder payOrder = new PayOrder();
        payOrder.setOrderId(orderId);
        payOrder.setPayUrl(form);
        payOrder.setStatus(Constants.OrderStatusEnum.PAY_WAIT.getCode());

        // 执行更新操作
        orderDao.updateOrderPayInfo(payOrder);

        // 返回对应的流水单
        return payOrder;
    }

    @Override
    public void changeOrderPaySuccess(String orderId) {
        PayOrder payOrderReq = PayOrder.builder()
                .orderId(orderId)
                .status(Constants.OrderStatusEnum.PAY_SUCCESS.getCode())
                .build();
        orderDao.changeOrderPaySuccess(payOrderReq);

        eventBus.post(JSON.toJSONString(payOrderReq));
    }

    @Override
    public boolean changeOrderClose(String orderId) {
        return orderDao.changeOrderClose(orderId);
    }

    @Override
    public List<String> queryNoPayNotifyOrder() {
        return orderDao.queryNoPayNotifyOrder();
    }

    @Override
    public List<String> queryTimeoutCloseOrderList() {
        return orderDao.queryTimeoutCloseOrderList();
    }
}


